// #include <mln/core/image/image2d.hh>
// #include <mln/make/image.hh>
// #include <mln/debug/println.hh>
// #include <mln/io/pbm/load.hh>
// #include <mln/io/pbm/save.hh>
// #include <mln/logical/not.hh>
// #include <mln/labeling/blobs.hh>
//// #include <mln/value/all.hh>
// #include <mln/core/neighb.hh>
#include <mln/all.hh>
#include <iostream>
#include <list>
#include <sstream>

using namespace mln;
using namespace mln::value;
using namespace mln::morpho;


// Fonction qui detecte les contours des zones d'une image.
// Pour l'instant, aucune differentiation n'est faite par rapport
// aux composante connexes..

template <typename I, typename N>
void
get_limits (I& ima, std::list<point2d>& list)
{
  mln_piter (I) p(ima.domain());
  mln_niter (N) n(c8 (), p);
  bool cont;

  for_all (p)
  {
    cont = false;
    if (ima(p) == literal::zero)
      {
	for_all (n)
	{
	  if (ima(n) == literal::one)
	    cont = true;
	}
	if (cont == true)
	  list.push_back (p);
      }
  }
}

// Fonction qui realise une ouverture.
// Deja presente dans milena, mais je n'etais pas sur de comment l'utiliser.

template <typename I>
I&
my_closing(I& ima)
{
  bool b[81] =	{ 0, 0, 0, 0, 1, 0, 0, 0, 0,
		  0, 0, 0, 1, 1, 1, 0, 0, 0,
		  0, 0, 1, 1, 1, 1, 1, 0, 0,
		  0, 1, 1, 1, 1, 1, 1, 1, 0,
		  1, 1, 1, 1, 1, 1, 1, 1, 1,
		  0, 1, 1, 1, 1, 1, 1, 1, 0,
		  0, 0, 1, 1, 1, 1, 1, 0, 0,
		  0, 0, 0, 1, 1, 1, 0, 0, 0,
		  0, 0, 0, 0, 1, 0, 0, 0, 0 };

  window2d win = convert::to<window2d>(b);

  ima = dilation (ima, win);
  ima = erosion (ima, win);

  return ima;
}

template <typename I>
std::list<I>&
get_labels (Image<I>& ima, unsigned min_nb_sites)
{
  label_16 nlabels;
  unsigned max = 0;
  unsigned index = 0;
  std::list<unsigned> index_list;
  std::list<unsigned>::iterator it;
  std::list<I>* image_list = new std::list<I>  ;
  std::stringstream ss;

  mln_ch_value(I, label_16) lbl = labeling::blobs(ima, c4(), nlabels);

  util::array<unsigned> count = labeling::compute(accu::meta::math::count (),
						  lbl, nlabels);

  for (unsigned i = 1; i <= nlabels; ++i)
    if (count[i] > min_nb_sites)
      {
	index_list.push_front (i);
      }

  std::cout << "Nb de composante selectionnee : " << index_list.size () << " sur "<< nlabels << std::endl;

  std::vector<typeof(lbl | (pw::value(lbl) == pw::cst(index)))> lbl_vect;

  int num = 0;
  for (it = index_list.begin (); it != index_list.end (); ++it)
    lbl_vect[num++] = (lbl | (pw::value(lbl) == pw::cst(*it)));

  num = 0;
  for (it = index_list.begin (); it != index_list.end (); ++it)
    {
      I *new_im = new I (duplicate (ima));

      ss.str( "" );
      ss << "first_step" << num << ".out.pbm"; 
      io::pbm::save(*new_im,  ss.str ());

      data::fill (*new_im, literal::one);
      data::fill ((*new_im | lbl_vect[num].domain()).rw(), literal::zero);

      ss.str( "" );
      ss << "inter_step" << num++ << ".out.pbm"; 
      io::pbm::save(*new_im,  ss.str ());

      lbl = labeling::blobs(*new_im, c4(), nlabels);
      count = labeling::compute(accu::meta::math::count (),
				lbl, nlabels);

      max = 0;
      for (unsigned i = 1; i <= nlabels; ++i)
	if (count[i] > max)
	  {
	    max = count[i];
	    index = i;
	  }

      typeof(lbl | (pw::value(lbl) == pw::cst(index)))  lbl_2 = (lbl | (pw::value(lbl) == pw::cst(index)));

      data::fill (*new_im, literal::one);
      data::fill((*new_im | lbl_2.domain()).rw(), literal::zero);
      image_list->push_back (*new_im);
    }
  return *image_list;
}


template <typename I>
void
make_ima_from_points (I& ima, std::list<point2d>& list)
{
  typename std::list<point2d>::const_iterator it;

  data::fill (ima, literal::zero);
  for (it = list.begin (); it != list.end (); ++it)
    ima(*it) = literal::one;
}


int
main (int argc, char** argv)
{
  image2d<bool> ima;
  std::list <point2d> list;
  std::list<image2d<bool> > image_list;
  std::list<image2d<bool> >::iterator it;
  std::stringstream ss;

  //  Image<image2d<bool > >* ima_ptr = new Image<image2d<bool > > (duplicate(ima));

  if (argc < 2)
    std::cout << "Usage : ./a.out input" << std::endl;

  //  trace::quiet = false;
  io::pbm::load (ima, argv[1]);

  ima = my_closing (ima);

  image_list = get_labels (ima, 10000);

  std::cout << "Taille ds main : " << image_list.size () << std::endl;

  //  get_limits<image2d<bool>, neighb2d> (ima, list);

  //  make_ima_from_points (ima, list);

  int num = 0;
  for (it = image_list.begin (); it != image_list.end (); ++it)
    {
      ss.str( "" );
      ss << "File" << num++ << ".out.pbm"; 
      io::pbm::save(*it, ss.str ());
    }
  return 0;
}
